package com.zeyu.framework.monitors.mongodb.web;

import com.google.common.collect.Lists;
import com.zeyu.framework.core.common.mapper.JsonMapper;
import com.zeyu.framework.core.persistence.Page;
import com.zeyu.framework.core.web.BaseController;
import com.zeyu.framework.core.web.Result;
import com.zeyu.framework.modules.sys.utils.UserUtils;
import com.zeyu.framework.monitors.mongodb.MongoDBCollector;
import com.zeyu.framework.monitors.mongodb.entity.CollectionStatus;
import com.zeyu.framework.monitors.mongodb.entity.DBStatus;
import com.zeyu.framework.monitors.mongodb.entity.MongoDBStatus;
import com.zeyu.framework.monitors.mongodb.service.MongoDBService;
import com.zeyu.framework.tools.report.charts.ChartData;
import com.zeyu.framework.tools.report.dynamic.ReportUtils;
import com.zeyu.framework.utils.Collections3;
import com.zeyu.framework.utils.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import java.util.List;

/**
 * mongodb 监控和操作controller
 * Created by zeyuphoenix on 16/8/27.
 */
@Controller
@RequestMapping(value = "/monitors/mongodb")
public class MongoDBController extends BaseController {

    // ================================================================
    // Constants
    // ================================================================

    // ================================================================
    // Fields
    // ================================================================

    @Autowired
    private MongoDBCollector mongoDBCollector;

    @Autowired
    private MongoDBService mongoDBService;

    // ================================================================
    // Constructors
    // ================================================================

    // ================================================================
    // Methods from/for super Interfaces or SuperClass
    // ================================================================

    // ================================================================
    // Public or Protected Methods
    // ================================================================

    /**
     * 页面
     */
    @RequestMapping(value = {"index", ""})
    public String index() {

        return "modules/monitors/mongodb";
    }

    /**
     * 获取最后一次监控的基本信息,这些信息不保存数据库
     */
    @ResponseBody
    @RequestMapping("current")
    public MongoDBStatus currentSatatus() {
        MongoDBStatus mongoDBStatus = mongoDBCollector.getMongoDBStatus();
        if (mongoDBStatus == null) {
            // 未扫描过则扫描一次
            mongoDBStatus = mongoDBCollector.getCurrentMongoDBServerStatus();
        }
        mongoDBStatus.setHostName(DateUtils.formatDateTimeLocal(mongoDBStatus.getUptime() * 1000L));
        return mongoDBStatus;
    }


    /**
     * 获取mongodb的数据库列表
     */
    @RequestMapping(value = "dbList")
    @ResponseBody
    public Page<DBStatus> dbList(HttpServletRequest request) {
        Page<DBStatus> page = new Page<>(request);
        page.setCount(1);
        page.setList(mongoDBCollector.getDbList());
        return page;
    }

    /**
     * 获取mongodb的数据库的collection列表
     */
    @RequestMapping(value = "collList")
    @ResponseBody
    public Page<CollectionStatus> collList(HttpServletRequest request) {
        Page<CollectionStatus> page = new Page<>(request);
        // 查询扩展
        String extraSearch = page.getDatatablesCriterias().getExtraSearch();
        // 转换
        DBStatus dbStatus = JsonMapper.getInstance().fromJson(extraSearch, DBStatus.class);
        String dbname = "admin";
        if (dbStatus != null) {
            dbname = dbStatus.getDbName();
        }
        page.setCount(1);
        page.setList(mongoDBCollector.getDbCollectionList(dbname));
        return page;
    }

    /**
     * 数据库的监控图表
     * 监控断掉的问题没办法
     */
    @RequestMapping(value = "chartData")
    @ResponseBody
    public ChartData chartData(int type) {

        ChartData chartData = new ChartData();

        // 默认查询是5分钟一次,则1小时12个,一天288个,一个月9000以内,使用带浮动条的全部查看
        List<MongoDBStatus> mongoDBStatusList = mongoDBService.findList(new MongoDBStatus());
        if (!Collections3.isEmpty(mongoDBStatusList)) {
            // 角度
            List<String> xAxis = Lists.newArrayList();
            // 指标
            List<List<Number>> series = Lists.newArrayList();

            // type --> 1:内存  2:连接  3:读写流量  4:操作数   5: 加载错误  6: 索引   7:网络请求

            // 转换数据
            for (MongoDBStatus mongoDBStatus : mongoDBStatusList) {
                xAxis.add(DateUtils.formatDate(mongoDBStatus.getTime(), "dd日HH:mm"));
                if (type == 1) {
                    // 内存
                    ReportUtils.addSerie(series, 4);
                    // '使用的物理内存大小(m)',
                    series.get(0).add(mongoDBStatus.getMemResident());
                    // '使用的虚拟内存大小(m)',
                    series.get(1).add(mongoDBStatus.getMemVirtual());
                    // '映射的内存大小(m)',
                    series.get(2).add(mongoDBStatus.getMemMapped());
                    // '具有日志的映射的内存大小',
                    series.get(3).add(mongoDBStatus.getMemMappedWithJournal());

                } else if (type == 2) {
                    // 连接
                    ReportUtils.addSerie(series, 2);
                    // '当前连接数',
                    series.get(0).add(mongoDBStatus.getConnectionsCurrent());
                    // '可用连接数',
                    series.get(1).add(mongoDBStatus.getConnectionsAvailable());

                } else if (type == 3) {
                    // 读写流量
                    ReportUtils.addSerie(series, 2);
                    // '网络读取字节数(byte)',
                    series.get(0).add(mongoDBStatus.getNetworkBytesIn());
                    // '网络发送字节数(byte)',
                    series.get(1).add(mongoDBStatus.getNetworkBytesOut());

                } else if (type == 4) {
                    // 操作数
                    ReportUtils.addSerie(series, 5);
                    // '插入操作数',
                    series.get(0).add(mongoDBStatus.getOpcountersInsert());
                    // '查询操作数',
                    series.get(1).add(mongoDBStatus.getOpcountersQuery());
                    // '更新操作数',
                    series.get(2).add(mongoDBStatus.getOpcountersUpdate());
                    // '删除操作数',
                    series.get(3).add(mongoDBStatus.getOpcountersDelete());
                    // '其它操作数',
                    series.get(4).add(mongoDBStatus.getOpcountersCommand());

                } else if (type == 5) {
                    // 加载错误
                    ReportUtils.addSerie(series, 1);
                    // '加载磁盘内容时发生页错误的次数',
                    mongoDBStatus.getExtraInfoPageFaults();
                    series.get(0).add(mongoDBStatus.getExtraInfoPageFaults());

                } else if (type == 6) {
                    // 索引
                    ReportUtils.addSerie(series, 4);
                    // '访问索引次数',
                    series.get(0).add(mongoDBStatus.getIndexCountersAccesses());
                    // '内存命中索引次数',
                    series.get(1).add(mongoDBStatus.getIndexCountersHits());
                    // '内存丢失索引次数',
                    series.get(2).add(mongoDBStatus.getIndexCountersMisses());
                    // '索引计数器重置次数',
                    series.get(3).add(mongoDBStatus.getIndexCountersResets());

                } else if (type == 7) {
                    // 网络请求
                    ReportUtils.addSerie(series, 1);
                    // '网络请求数',
                    series.get(0).add(mongoDBStatus.getNetworkNumRequests());

                }
            }

            chartData.setxAxis(xAxis);
            chartData.setSeries(series);
        }

        return chartData;
    }


    /**
     * 释放内存，注意锁和数据丢失问题
     */
    @RequestMapping(value = "releaseMemory")
    @ResponseBody
    public Result releaseMemory() {
        Result result = new Result();
        if (MODE_DEMO) {
            result.setStatus(Result.ERROR);
            result.setMessage("演示模式，不允许操作!");
            return result;
        }
        if (!UserUtils.getUser().isAdmin()) {
            result.setStatus(Result.ERROR);
            result.setMessage("只能使用管理员用户才可以操作!");
            return result;
        }
        mongoDBCollector.releaseMemory();
        result.setStatus(Result.SUCCESS);
        result.setMessage("数据库备份成功");
        return result;
    }

    /**
     * 数据库还原
     */
    @RequestMapping(value = "releaseDisk")
    @ResponseBody
    public Result releaseDisk() {
        Result result = new Result();
        if (MODE_DEMO) {
            result.setStatus(Result.ERROR);
            result.setMessage("演示模式，不允许操作!");
            return result;
        }
        if (!UserUtils.getUser().isAdmin()) {
            result.setStatus(Result.ERROR);
            result.setMessage("只能使用管理员用户才可以操作!");
            return result;
        }
        mongoDBCollector.releaseDisk();
        result.setStatus(Result.SUCCESS);
        result.setMessage("数据库还原成功");
        return result;
    }

    /**
     * 数据库重新启动
     */
    @RequestMapping(value = "restart")
    @ResponseBody
    public Result restart() {
        Result result = new Result();
        if (MODE_DEMO) {
            result.setStatus(Result.ERROR);
            result.setMessage("演示模式，不允许操作!");
            return result;
        }
        if (!UserUtils.getUser().isAdmin()) {
            result.setStatus(Result.ERROR);
            result.setMessage("只能使用管理员用户才可以操作!");
            return result;
        }
        // TODO
        result.setStatus(Result.SUCCESS);
        result.setMessage("MongoDB数据库重新启动成功");
        return result;
    }

    // ================================================================
    // Getter & Setter
    // ================================================================

    // ================================================================
    // Private Methods
    // ================================================================

    // ================================================================
    // Inner or Anonymous Class
    // ================================================================

    // ================================================================
    // Test Methods
    // ================================================================

}
